import { Injectable } from '@nestjs/common';
import { SseService } from '../com-sse/sse.service';
import { RedisService } from '../../database/redis/redis.service';
import { MongodbService } from '../../database/mongodb/mongodb.service';
import { ComExcelToolService } from '../com-excel-tool/com-excel-tool.service';
import superagent, { Response } from 'superagent';
import { SCJCConstants } from './scjc.service.type';
import { BusinessException } from '../../types/exception/business.exception';
import { ERR_MSG } from '../../types/errcode';
import * as _ from 'lodash';
import { v4 as uuidv4 } from 'uuid';

@Injectable()
export class ScjcService {
  constructor(
    private readonly _sseService: SseService,
    private readonly _redisService: RedisService,
    private readonly _mongodbService: MongodbService,
    private readonly _comExcelToolService: ComExcelToolService,
  ) {}

  private AllData = {
    GS: {
      GS_GB_Number: 'RF 67#',
      GS_Weight: (Math.random() * 1000).toFixed(2) + 't',
      GS_WenDu: (Math.random() * 1000).toFixed(2) + '℃',
      GS_CG_Time: "1'22",
      GS_C: (Math.random() * 10).toFixed(2) + '',
      GS_Si: (Math.random() * 10).toFixed(2),
      GS_Mn: (Math.random() * 10).toFixed(2),
      GS_P: (Math.random() * 10).toFixed(2),
      GS_S: (Math.random() * 10).toFixed(2),
    },
    CL: {
      CL_YQ_Height: '1635.22 mm',
      CL_Time: "13'39",
      CL_LuZI_WenDu: '1230.22℃',
      CL_YQ_Time: "1'22",
    },
    CZ: {
      CZ_ZP_Status: '就位',
      CZ_Time: "1'39",
    },
    DT: {
      DT_GB_Number: 'RF 67#',
      DT_TS_Weight: '120.00t',
      DT_TS_WenDu: '1230.22℃',
      DT_C: '4.500',
      DT_Si: '0.190',
      DT_Mn: '0.143',
      DT_P: '0.190',
      DT_S: '0.190',
    },
    FG: {
      FG_Number: 'L1G2F3C4',
      FG_TC_Weight: '120.00t',
      FG_TaiChe_Weight: '1230.22℃',
      FG_Type: '普通废钢、合金废钢...',
      FG_HJ_Type: '铬、镍、钼',
    },
    JZ: {
      JZ_YQ_Height: '1635.22 mm',
      JZ_CY_Time: "0'39",
      JZ_XHDQ_Time: '120.22 Nm³',
      JZ_Time: "03'22",
      JZ_LC_Thickness: '356.12 mm',
    },
  };

  // 模拟发送sse数据
  async getAllData() {
    //   this.sendEvent('simulateSSEData', this.generateMockData());
    this.AllData.GS = {
      GS_GB_Number: 'RF 67#',
      GS_Weight: (Math.random() * 1000).toFixed(2) + 't',
      GS_WenDu: (Math.random() * 1000).toFixed(2) + '℃',
      GS_CG_Time: "1'22",
      GS_C: (Math.random() * 10).toFixed(2) + '',
      GS_Si: (Math.random() * 10).toFixed(2),
      GS_Mn: (Math.random() * 10).toFixed(2),
      GS_P: (Math.random() * 10).toFixed(2),
      GS_S: (Math.random() * 10).toFixed(2),
    };
    this._sseService.sendEvent('processData', this.AllData);
    return this.AllData;
  }

  async setRedisData() {
    await this._redisService.setObject('GS', this.AllData, 60); // 1小时过期
    return { mag: '保存成功' };
  }

  async getRedisData() {
    const obj = await this._redisService.getObject('GS');
    return { obj };
  }

  // 请求第三方钉钉数据
  async getDingDingData() {
    // 接口请求 获取新token
    const api = `${process.env.DINGDING_LOGIN}/v1.0/oauth2/accessToken`;
    // 请求体
    const body = {
      // 已创建的企业内部应用的AppKey
      appKey: process.env.DINGDINGAPPKEY,
      // 已创建的企业内部应用的AppSecret
      appSecret: process.env.DINGDINGAPPSECRET,
    };

    // 请求
    const res: Response = await superagent.post(api).send(body);

    // 获取 AccessToken 格式的返回
    const resData = res.text ? JSON.parse(res.text) : res.body;
    // 返回 accessToken
    return {
      accessToken: resData.accessToken,
    };
  }

  // 下载模板
  async downLoadExcelTemplate(query: any = { type: 'test' }) {
    let url;

    let addr = '';
    if (process.env.NOWENV === 'prod') {
      // 地址
      addr = process.env.FILE_EXPOSE_IP;
    } else {
      // 地址
      addr = `http://${process.env.SERVER_ADDRESS}:${process.env.SERVER_PORT}`;
    }
    switch (query.type) {
      case 'test':
        url = addr + '/template/数据导入模板.xlsx';
        break;
      default:
        return { msg: '模版下载异常' };
    }
    return { url };
  }

  // 导出表格数据 - 从数据库里面取
  async excelExport() {
    const headers = Object.keys(SCJCConstants.DepartMap);
    const fields = Object.values(SCJCConstants.DepartMap);

    // 构建聚合管道
    const pipeline: any[] = [];

    // 这块可以现根据查询条件添加对应的查询match
    //

    pipeline.push({ $sort: { created_at: -1, sort: 1 } }); // 先按按时间倒序，再按sort正序 1正序 -1倒序

    // 构建 $addFields 阶段来扁平化处理嵌套字段
    const addFieldsStage = {
      $addFields: {},
    };

    fields.forEach((field, index) => {
      const key = headers[index];
      addFieldsStage.$addFields[key] = { $ifNull: [`$${field}`, null] };
    });

    pipeline.push(addFieldsStage);

    // 构建 $project 阶段来移除嵌套字段并保留重新命名后的字段
    const projectStage = {
      $project: { _id: 0 },
    };

    headers.forEach((header) => {
      projectStage.$project[header] = 1;
    });

    pipeline.push(projectStage);

    const list = await this._mongodbService.DepartModel.aggregate(pipeline);

    // 这块获取到数据后，可以把数据二次处理，比如将其根据字典转化，字段重新赋值等
    //

    const url = await this._comExcelToolService.createStyledExcel(
      headers,
      list,
      '测试数据库数据导出.xlsx',
      'Test',
    );

    return { url };
  }

  // 导入表格数据 - 直接存数据库里面
  async excelImport(file: Express.Multer.File) {
    if (!file) {
      throw new BusinessException(ERR_MSG.CHECK, '请上传文件');
    }

    const jsonData = await this._comExcelToolService.handleExcelFile(file);

    // 判断jsonData是否为空对象
    if (_.isEmpty(jsonData)) {
      throw new BusinessException(ERR_MSG.CHECK, '表格数据为空');
    }

    const requiredIndices = [0, 1, 2, 3, 4]; // 不为空的下标索引
    const dateIndices = [3, 4]; // 时间格式下标索引数组
    const dictionaryIndices = [0]; // 字典类型下标数组

    // 进行数据检查
    const error = await this.checkExcelData(
      jsonData.slice(1),
      jsonData[0],
      requiredIndices,
      dateIndices,
      dictionaryIndices,
    );
    // 校验error是否为空 或者 error.length>0
    if (error.length > 0) {
      return { error };
    } else {
      const result = await this.assembleInitialData(jsonData.slice(1));
      await this._mongodbService.DepartModel.insertMany(result);
      return { mag: '导入成功' };
    }
  }

  // 处理数据成可插入数据库的格式
  async assembleInitialData(jsonData) {
    const fieldNames = [
      'departName',
      'parentId',
      'sort',
      'createdAt',
      'updatedAt',
    ];
    const dataList = [];

    const promises = jsonData.map(async (item) => {
      if (_.isEmpty(item)) {
        return;
      }
      const info = {};
      for (let i = 0; i < fieldNames.length; i++) {
        info[fieldNames[i]] = item[i];
      }

      // 重新赋值id
      info['id'] = uuidv4().replace(/-/g, '');

      return info;
    });
    const resolvedData = await Promise.all(promises);
    resolvedData.forEach((item) => {
      if (item) {
        dataList.push(item);
      }
    });
    return dataList;
  }

  // 检查表格数据
  async checkExcelData(
    jsonData,
    title,
    requiredIndices,
    dateIndices,
    dictionaryIndices,
  ) {
    const errors = [];
    // jsonData中移除 空的数组
    jsonData = jsonData.filter((item) => {
      if (item.length === 0) {
        return false;
      }
      return true;
    });
    if (jsonData.length > 0) {
      // 对原始数据进行格式校验
      for (let i = 0; i < jsonData.length; i++) {
        const item = jsonData[i];
        const currentErrors = [];
        // 校验不为空的字段
        for (const index of requiredIndices) {
          if (!this.isRequired(item[index])) {
            currentErrors.push(`${title[index]}不能为空`);
          }
        }

        // 校验时间格式的字段
        for (const index of dateIndices) {
          const dateString = item[index];
          if (dateString && !this.isValidDate(dateString)) {
            currentErrors.push(`${title[index]} 字段日期格式不正确`);
          }
        }

        // 校验字典类型的字段
        for (const index of dictionaryIndices) {
          const value = item[index];
          const type = title[index];
          if (!(await this.isValidDictionaryValue(value, type))) {
            currentErrors.push(`${title[index]}字段中在字典表中不存在`);
          }
        }

        if (currentErrors.length > 0) {
          errors.push({ row: i + 2, errors: currentErrors });
        }
      }
    }

    return errors;
  }

  isRequired(value: any): boolean {
    if (value === null || value === undefined || value === '') {
      return false;
    }
    return true;
  }

  isValidDate(dateString: string): boolean {
    // 校验是否是 yyyy-MM-dd 时间格式
    const regex = /^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[12]\d|3[01])$/;
    return regex.test(dateString);
  }

  async isValidDictionaryValue(value: string, type: string) {
    let dictionList;
    if (type === '名称') {
      // dictionList = await this._mongodbService.DictionaryModel.find({
      //   dictKey: 'DICT_SKILLLEVEL',
      // });
      dictionList = [
        {
          dictKey: 'DICT_TASK_PROPERTY',
          dictValue: [
            {
              dictCode: 'DICT_TASK_PROPERTY',
              itemName: '测试部门3',
              itemCode: '3',
            },
            {
              id: 'ff8081818fd1cc3601907badae3703e3',
              dictCode: 'DICT_TASK_PROPERTY',
              itemName: '测试部门4',
              itemCode: '4',
            },
          ],
        },
      ];
    }

    if (!dictionList || !dictionList[0].dictValue) {
      return false;
    }

    const exists = dictionList[0].dictValue.some(
      (item) => item.itemName === value,
    );
    return exists;
  }
}
